mod constants;
mod dataset;
pub mod devices;
mod handlers;
mod ipfs;
mod meta;
mod request;
mod robots;
pub mod task;

use crate::socket_capnp::{peer_http_response};
use anyhow::{anyhow, Result};
use tauri::{
    http::{
        header::{HeaderName, HeaderValue},
        Request as HttpRequest, Response as HttpResponse,
    },
    plugin::{Builder, TauriPlugin},
    AppHandle, Manager, Runtime,
};


use capnp::message::{ReaderOptions, TypedReader};

pub mod socket_capnp {
    include!(concat!(env!("OUT_DIR"), "/proto/socket_capnp.rs"));
}

fn response(data: Result<Vec<u8>>) -> Result<HttpResponse<Vec<u8>>> {
    let data = data?;

    tracing::debug!("请求成功返回数据:{}", data.len());
    let reader = capnp::serialize_packed::read_message(data.as_slice(), ReaderOptions::new())?;

    let response_reader = TypedReader::<_, peer_http_response::Owned>::new(reader);

    //
    let rr = response_reader
        .get()
        .map_err(|err| anyhow::anyhow!("response_reader获取失败:{}", err))?;
    let body = rr
        .reborrow()
        .get_body()
        .map_err(|err| anyhow::anyhow!("response_reader获取失败:{}", err))?;
    let status = rr.reborrow().get_status();

    let response_headers = rr
        .reborrow()
        .get_headers()
        .map_err(|err| anyhow::anyhow!("response_reader获取失败:{}", err))?;

    let mut builder = tauri::http::Response::builder();

    let headers = builder.headers_mut().map_or(Err(anyhow!("")), |v| Ok(v))?;

    //  header
    response_headers.get_entries()?.iter().for_each(|entry| {
        let key = entry.get_key();
        let value = entry.get_value();

        if key.is_ok() && value.is_ok() {
            //

            //
            headers.insert(
                HeaderName::from_bytes(key.unwrap().to_str().unwrap().as_bytes()).unwrap(),
                HeaderValue::from_str(value.unwrap().to_str().unwrap()).unwrap(),
            );
        }
    });

    Ok(builder.status(status).body(body.to_vec())?)
}

pub fn rrapp_protocol<R: Runtime>(
    _app_handle: &AppHandle<R>,
    request: HttpRequest<Vec<u8>>,
) -> HttpResponse<Vec<u8>> {
    let current_result = tauri::async_runtime::TokioHandle::try_current();

    let f = async move {
        // do something async
        crate::devices::devices_device_request(request).await
    };

    let result = match current_result {
        Ok(current) => current.block_on(f),
        Err(_) => {
            let rt = tauri::async_runtime::TokioRuntime::new().unwrap();
            rt.handle().block_on(f)
        }
    }
    .map_err(|_err| anyhow!(""));

    match response(result) {
        Ok(res) => res,
        Err(err) => {
            let message = format!("{}", err).into_bytes();
            tauri::http::Response::builder()
                .header("Content-Length", message.len())
                .status(404)
                .body(message)
                .unwrap()
        }
    }
}

/// Initializes the plugin.
pub fn init<R: Runtime>() -> TauriPlugin<R> {
    Builder::new("rrai-idns")
        .invoke_handler(tauri::generate_handler![
            handlers::rrai_cloud_get,
            handlers::rrai_cloud_post,
            //
            handlers::set_context_value,
            handlers::get_context_value,
            handlers::schema_by_model,
            //
            handlers::dataset_create_row,
            handlers::update_dataset_row,
            handlers::query_dataset_row,
            handlers::remove_dataset_row,
            handlers::dataset_rows_search,
            handlers::dataset_rows_search_by_model,
            handlers::dataset_rows_search_owned,
            handlers::dataset_create_by_model_id,
            //
            handlers::tasks_task_publish,
            handlers::tasks_worker_wakeup,
            handlers::tasks_task_take,
            handlers::tasks_task_query_by_id,
            handlers::tasks_task_process_result,
            //
            handlers::ipfs_files_search,
            handlers::ipfs_files_create_with_local_file,
            handlers::ipfs_files_create_with_bytes_content,
            handlers::ipfs_files_create_with_string_content,
            handlers::ipfs_files_create,
            handlers::ipfs_files_mkdirs,
            handlers::ipfs_files_update,
            handlers::ipfs_files_remove,
            handlers::ipfs_string_content,
            handlers::ipfs_pins_status,
            handlers::ipfs_pins_unpin,
            handlers::ipfs_pins_pin,
            handlers::devices_device_login,
            handlers::devices_device_get_peer_id,
            handlers::devices_device_search,
            handlers::robots_query_by_peer_id,
            handlers::robots_query_local_robots,
            handlers::robots_query_by_id,
        ])
        .setup(|app, _plugin| {
            app.manage(handlers::ContextState::default());
            Ok(())
        })
        .build()
}
